from common_util.hive_util.hive_conn import HiveUtil
from common_util.hive_util.hive_conf import hive_dic


# HiveUtil：hive库的python连接池，用于hive的查询，需要开启hiveserver2，目前公司hiveserver2支持的不是特别好，只能做一些简单的操作
# 配置文件在hive_dic中
if __name__ == '__main__':
    # 创建连接（单利模式，省内存，local_my_test是hive_dic的key）
    conn = HiveUtil.get_conn('local_my_test')
    # 获取游标
    cursor = conn.cursor()
    # 执行sql
    cursor.execute("show database")
    # 将结果加载到result中，结果为元祖构成的列表，列表中每个元祖是一行
    result = cursor.fetchall()
    # 遍历结果
    for row in result:
        print(row)
    # 断开连接，关闭数据库，如果开启多个库的连接，可使用close()，如果单个，也可以使用conn.close()
    HiveUtil.close_all()
    # conn.close()

from common_util.mysql_util.mysql_conn import MysqlUtil
from common_util.mysql_util.mysql_conf import mysql_dic

# MysqlUtil：mysql库的python连接池，用于mysql的查询
# 配置文件在mysql_dic中
if __name__ == '__main__':
    # 创建连接（单利模式，省内存，local_my_test是hive_dic的key）
    conn = MysqlUtil.get_conn('test_db')
    # 获取游标
    cursor = conn.cursor()
    # 执行sql
    cursor.execute("show database")
    # 将结果加载到result中，结果为元祖构成的列表，列表中每个元祖是一行
    result = cursor.fetchall()
    # 遍历结果
    for row in result:
        print(row)
    # 断开连接，关闭数据库，如果开启多个库的连接，可使用close()，如果单个，也可以使用conn.close()
    MysqlUtil.close_all()
    # conn.close()


from common_util.psql_util.psql_conn import PsqlUtil
from common_util.psql_util.psql_conf import psql_dic

# PsqlUtil：postgresql库的python连接池，用于postgresql的查询
# 配置文件在psql_dic中
if __name__ == '__main__':
    # 创建连接（单利模式，省内存，local_my_test是hive_dic的key）
    conn = PsqlUtil.get_conn('test_db')
    # 获取游标
    cursor = conn.cursor()
    # 执行sql
    cursor.execute("show database")
    # 将结果加载到result中，结果为元祖构成的列表，列表中每个元祖是一行
    result = cursor.fetchall()
    # 遍历结果
    for row in result:
        print(row)
    # 断开连接，关闭数据库，如果开启多个库的连接，可使用close()，如果单个，也可以使用conn.close()
    PsqlUtil.close_all()
    # conn.close()


from common_util.redis_util.redis_conn import RedisUtil
from common_util.redis_util.redis_conf import redis_dic

# RedisUtil：redis库的python连接池，用于redis的查询
# 配置文件在redis_dic中
# 包中还有简单的订阅和发布的例子，有时间可以自己研究下
if __name__ == '__main__':
    # 创建连接（单利模式，省内存，local_my_test是hive_dic的key）
    r = RedisUtil.get_conn('test_db')
    # 操作redis
    r.set('name', 'lirui')
    r.get('name')
    # 断开当前连接池的所有连接，可是使用close_by_name关闭单个连接
    RedisUtil.close_all()
    RedisUtil.close_by_name('test_db')
    # conn.close()


from common_util.system_util.system_util import get_local_ip

# 一些系统的工具，开发中，目前能用的不多
if __name__ == '__main__':
    # 获取本地ip
    local_ip = get_local_ip()


from common_util.datetime_util import *

# 一些日期的相关的处理，详细用法自己体会
if __name__ == '__main__':
    print('5天之前：', add_date(-5).strftime('%Y-%m-%d'))
    print('本月第一天：', this_month_first().strftime('%Y-%m-%d'))
    print('本月最后一天：', this_month_last().strftime('%Y-%m-%d'))
    print('2019-5-18 的当月的第一天：', month_first(datetime.datetime(2019, 5, 18, 20, 18, 12)).strftime('%Y-%m-%d'))
    print('2019-5-18 的当月的最后一天：', month_last(datetime.datetime(2019, 5, 18, 20, 18, 12)).strftime('%Y-%m-%d'))
    print('11个月之后的当月第一天：', next_n_month_first(11).strftime('%Y-%m-%d'))
    print('15个月之前的当月最后一天：', next_n_month_last(-15).strftime('%Y-%m-%d'))
    print('2019-02-03 字符串转时间戳：', dtstr_to_timestamp('2019-02-03', '%Y-%m-%d'))
    print('2019-05-18 日期格式转时间戳：', dt_to_timestamp(datetime.datetime(2019, 5, 18)))
    print('时间戳转日期格式：', timestamp_to_dt(dtstr_to_timestamp('2019-02-03', '%Y-%m-%d')).strftime('%Y-%m-%d'))


from common_util.email_util import EmailUitl

# smtp邮件类，可支持发送附件，需要smtp服务，很可惜，搜狗没有开这个服务
# 邮箱用的自己的账号和密码，想修改的话，可以考虑看下类的内部实现
if __name__ == '__main__':
    # 附件文件路径
    _filename = '../file_log/run_logs/run_log.2018-05-07'
    # 邮件主题
    _subject = '我的邮件类'
    # 邮件正文
    _content = '12312313'
    # 收件人
    _receiver_list = ['270239148@qq.com']
    # 抄送人员
    _cc_list = ['lirui215278@sogou-inc.com']
    # 暗送人员
    _bcc_list = ['lirui215278@sogou-inc.com']

    # 邮件添加附件
    EmailUitl.add_file_content(_filename)
    # 邮件添加正文
    EmailUitl.add_content(content=_content, mime_type='html', _encode='utf-8')
    # 邮件设置发送头信息（头信息包含主题，收件人，抄送人，暗送人）
    EmailUitl.set_mail_header(subject=_subject, receiver_list=_receiver_list, cc_list=_cc_list, bcc_list=_bcc_list)
    # 发送邮件
    EmailUitl.send()


from common_util.excel_util import ExcelUtil

# 适合批量数据写进excel
if __name__ == '__main__':
    # 创建excel对象
    wb = ExcelUtil()
    # 创建表头数据列表
    _head_data = list(range(10))
    # 创建内容数据列表
    _result_data = [list(range(11, 20)), list(range(21, 30))]
    # 写入excel（参数分别为sheet名字，表头列表，数据列表）
    wb.write_excel('数字列表', _head_data, _result_data)
    # 调整excel格式，包括字体和列宽（很好用的一个函数，可以删除掉空的sheet，将首行加粗，字体设置成微软雅黑，列宽自适应等）
    wb.set_fit()
    # 保存excel
    wb.save(filename='E:/测试数据.xlsx')


from common_util.exchange_mail_util import ExchangeUtil

# 搜狗邮箱发邮件的福音
if __name__ == '__main__':
    # 主题
    subject = 'exchange邮件'
    # 收件人列表
    receiver_list = ['270239148@qq.com', 'lirui_gydx@163.com']
    # 抄送列表
    cc_receiver_list = ['lirui_gydx@sina.com']
    # 暗送列表
    bcc_receiver_list = ['lirui215278@sogou-inc.com']
    # 正文
    content = '这是正文'
    # 附件路径
    file_name = '../file_log/run_logs/run_log.2018-05-07'

    # 初始化账户
    mail = ExchangeUtil(subject, receiver_list, cc_receiver_list, bcc_receiver_list)
    # 设置正文
    mail.set_content(content)
    # 添加附件（可多次添加）
    mail.add_file(file_name)
    # 发送并保存邮件，这里发送完之后，自己的发件箱也有保存此邮件
    mail.send()


from common_util.log_util import get_logger

# 日志的使用
if __name__ == '__main__':
    # 实例化日志对象（日志会默认写到../file_log/run_logs/run_log.日期 文件中）
    logger = get_logger()
    # 几种类型的日志打印（写入等级为info，打印等级为debug）
    logger.debug("debug日志")
    logger.info("info日志")
    logger.error("error日志")
    logger.warning("warning日志")

    # 捕获异常并打印到日志
    try:
        logger.info('计算除数为0的式子')
        a = 1/0
        logger.info('计算的结果为：%s' % a)
    except Exception as e:
        logger.error(e)
        logger.error(traceback.format_exc())


from common_util.multi_process_util import multi_exec_func, multi_exec_func_result
from multiprocessing import Manager
import os

# 测试用的函数，用于测试上面定义的多进程函数
if __name__ == '__main__':

    # 专门用于多进程的类装饰器，用于打印此进程的pid，使用方法如下：
    # func_decorate = OutputPid(func)
    # func_decorate()
    class OutputPidAndName:
        def __init__(self, func):
            self.func = func

        def __call__(self, *args, **kwargs):
            print("当前进程的pid为：%s，函数名为：%s" % (os.getpid(), self.func.__name__))
            # 注意这里要return结果，callback函数才能正常收到参数
            return self.func(*args, **kwargs)

    # 初始化进程锁（注意在使用进程池的时候要用Manager的Lock）
    lock = Manager().Lock()
    path = os.path.dirname(os.path.abspath(__file__))
    logger = get_logger(log_path=path + '/tem.log')

    # 初始化参数
    argvs = [('http://maoyan.com/board/' + str(x), lock) for x in range(1, 11)]
    # 初始化文件，用于加锁测试
    f = open('temfile.txt', 'a', encoding='utf-8')

    # 测试多进程的函数，内部包含进程锁（注意，在多进程下，暂时不是使用装饰器，此问题待解决）
    def get_page(url, lock=lock):
        global f
        print('(进程 %s) 正在下载页面 %s' % (os.getpid(), url))
        lock.acquire()
        f.write('(进程 %s) 正在下载页面 %s' % (os.getpid(), url) + '\n')
        f.flush()
        logger.info('(进程 %s) 正在下载页面 %s' % (os.getpid(), url))
        lock.release()
        time.sleep(1)
        # 返回参数用于回调函数的参数
        return url + 'result'

    # get_page的回调函数，接收get_page返回的数据作为参数，继续执行
    def parse_page(page_content):
        print('<进程 %s> 正在解析页面: %s' % (os.getpid(), page_content))

    # get_page函数用OutputPidAndName装饰器包裹，注意此处一定要用类装饰器，且不能使用@装饰器的语法糖
    get_page_decorate = OutputPidAndName(get_page)

    # 无返回值的多进程执行
    multi_exec_func(get_page_decorate, argvs=argvs, callback=parse_page, process_num=10)

    # 带返回值的多进程执行，注意res_list接收到的是get_page主函数的返回结果，而非callback函数的返回结果
    res_list = multi_exec_func_result(get_page_decorate, argvs=argvs, callback=parse_page, process_num=10)
    for res in res_list:
        print(res.get())


# common_util/split_file_util.py，目前是以脚本的形式存在的，主要用于切分文件，在命令行中执行，后期会抽象成函数或工具类，放到system_util中去
# 用法：python3 split_file_util.py file_name result_dir split_num








